package com.yvdelx.cyclowomen.utility;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

/**
 * Utility for date
 * Created by ydelvaux on 22/02/14.
 */
public class DateUtility {

    // Date format for all app
    private static DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");

    /**
     * Create date from his long representative
     *
     * @param dateTime Long
     * @return Date
     */
    public static Date getDateFromLong(Long dateTime) {
        return new Date(dateTime);
    }

    /**
     * Return the date with the format dd/MM/yyyy
     *
     * @param date Date
     * @return String to format dd/MM/yyyy
     */
    public static String dateToString(Date date) {
        return dateFormat.format(date);
    }

    /**
     * Return the long corresponding to the date
     *
     * @param date Date
     * @return Long
     */
    public static Long getLongFromDate(Date date) {
        Calendar calendar = getCalendarInstance();
        calendar.setTime(date);
        return calendar.getTimeInMillis();
    }

    public static Date getDateFromString(String dateString) throws ParseException {
        return dateFormat.parse(dateString);
    }

    /**
     * Return the date - 1 day
     *
     * @param date Date
     * @return Date
     */
    public static Date previousDate(Date date) {
        Calendar calendar = getCalendarInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, -1);
        return calendar.getTime();
    }

    /**
     * Return the date + 1 day
     *
     * @param date Date
     * @return Date
     */
    public static Date nextDate(Date date) {
        Calendar calendar = getCalendarInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, 1);
        LogUtility.debug(DateUtility.class, "Time Zone : " + calendar.getTimeZone().getDisplayName());
        return calendar.getTime();
    }

    /**
     * Get the date from :
     *
     * @param day   Day of month
     * @param month month
     * @param year  year
     * @return date
     */
    public static Date getDate(Integer day, Integer month, Integer year) throws ParseException {
        Calendar calendar = getCalendarInstance();
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.YEAR, year);
        String dateStr = dateFormat.format(calendar.getTime());
        LogUtility.debug(DateUtility.class, "Time Zone : " + calendar.getTimeZone().getDisplayName());
        return getDateFromString(dateStr);
    }

    /**
     * Get today date
     *
     * @return date
     */
    public static Date getDate() throws ParseException {
        Calendar calendar = getCalendarInstance();
        String dateStr = dateFormat.format(calendar.getTime());
        LogUtility.debug(DateUtility.class, "Time Zone : " + calendar.getTimeZone().getDisplayName());
        return getDateFromString(dateStr);
    }

    /**
     * Compute the number of day in month
     *
     * @param year  Integer
     * @param month Integer
     * @return Integer Result of compute
     */
    public static Integer getNumberOfDayOfMonth(Integer year, Integer month) {
        Calendar calendar = getCalendarInstance();
        //noinspection MagicConstant,ResourceType
        calendar.set(year, month - 1, 1);
        return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    /**
     * Get the string representation of the month in parameter
     *
     * @param month Integer
     * @return String representation
     */
    public static String getMonthNumberAsString(Integer month) {
        Calendar calendar = getCalendarInstance();
        calendar.set(Calendar.MONTH, month - 1);
        return String.valueOf(calendar.get(Calendar.MONTH));
    }

    /**
     * Return true if the month in parameter is the current month
     *
     * @param month Integer
     * @return Boolean
     */
    public static boolean isCurrentMonth(Integer month) {
        Calendar calendar = getCalendarInstance();
        Integer monthCalendar = calendar.get(Calendar.MONTH) + 1;
        return monthCalendar.equals(month);
    }


    /**
     * Format the date from the pattern if it's not null
     * It's null use pattern dd/MM/yyyy
     *
     * @param date    Date
     * @param pattern String
     * @return String
     */
    public static String getStringFromDate(Date date, String pattern) {
        if (pattern == null) {
            return dateToString(date);
        } else {
            DateFormat mDateFormat = new SimpleDateFormat(pattern);
            return mDateFormat.format(date);
        }
    }

    /**
     * This method returns the date in string format corresponding to the pattern
     *
     * @param dateLong Long
     * @param pattern  String
     * @return Date string
     */
    public static String dateToString(Long dateLong, String pattern) {
        Date date = new Date(dateLong);
        return getStringFromDate(date, pattern);
    }

    /**
     * This method returns the date with this month and this year
     *
     * @param month Integer
     * @param year  Integer
     * @return Date
     */
    public static Date getDate(Integer month, Integer year) {
        Calendar calendar = getCalendarInstance();
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.YEAR, year);
        LogUtility.debug(DateUtility.class, "Time Zone : " + calendar.getTimeZone().getDisplayName());
        return calendar.getTime();
    }


    /**
     * Instantiate the calendar with local Locale
     *
     * @return Calendar
     */
    private static Calendar getCalendarInstance() {
        return Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    }

    /**
     * Instantiate the calendar with the date
     *
     * @param date Date
     * @return Calendar
     */
    private static Calendar getCalendarInstance(Date date) {
        Calendar calendar = getCalendarInstance();
        calendar.setTime(date);
        LogUtility.debug(DateUtility.class, "Time Zone : " + calendar.getTimeZone().getDisplayName());
        return calendar;
    }

    /**
     * Return true if the date is between dateDebut and dateFin
     *
     * @param date      Date
     * @param dateDebut Date
     * @param dateFin   Date
     * @return Boolean
     */
    public static boolean isBetween(Date date, Date dateDebut, Date dateFin) {
        Integer[] yearMonth = getYearMonth(date);
        Integer[] yearMonthDeb = getYearMonth(dateDebut);
        Integer[] yearMonthFin = new Integer[2];
        // if dateFin doesn't exist, then the end is put on the next month, next year.
        if (dateFin != null)
            yearMonthFin = getYearMonth(dateFin);
        else {
            yearMonthFin[0] = yearMonth[0] + 1;
            yearMonthFin[1] = yearMonth[1] + 1;
        }

        return yearMonth[0] >= yearMonthDeb[0]
                && yearMonth[0] <= yearMonthFin[0]
                && yearMonth[1] >= yearMonthDeb[1]
                && yearMonth[1] <= yearMonthFin[1];
    }

    /**
     * Get the year and the month of a date
     *
     * @param date Date
     * @return Integer[];
     */
    private static Integer[] getYearMonth(Date date) {
        Integer[] result = new Integer[2];
        Calendar calendar = getCalendarInstance(date);
        result[0] = calendar.get(Calendar.YEAR);
        result[1] = calendar.get(Calendar.MONTH);
        return result;
    }
}
